package com.transaction.simulate.service.impl;

import com.transaction.common.base.PageInfo;
import com.transaction.common.util.*;
import com.transaction.simulate.mapper.AccountMapper;
import com.transaction.simulate.mapper.ChannelMapper;
import com.transaction.simulate.mapper.DictMapper;
import com.transaction.simulate.model.dto.*;
import com.transaction.simulate.model.vo.ChannelAccountVo;
import com.transaction.simulate.service.AccountService;
import com.transaction.simulate.util.AssembleFileUtil;
import com.transaction.simulate.util.SequenceUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

@Service
public class AccountServiceImpl implements AccountService {

    private static Logger LOGGER = LoggerFactory.getLogger(AccountServiceImpl.class);

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private ChannelMapper channelMapper;

    @Autowired
    private SequenceUtil sequenceUtil;

    @Autowired
    private DictMapper dictMapper;

    /**
     * 生成身份证号
     * @Title: generateIdentityNoList
     * @author: dy.yin 2021/8/19 14:30
     */
    @Override
    public String generateIdentityNo() {
        //1.随机1个区号
        County county = accountMapper.getRandomCounty();
        //2.随机一个年月日
        String birthday = DateUtil.randomBirthDay();
        //3.随即一个警局所在地
        String location = CodeUtil.randomLocation();
        //4.随机一个性别
        String sex = CodeUtil.randomSex();
        //5.把这些值和起来，组成前17位
        String prefix = buildPrefix17(county,birthday,location,sex);
        //6.计算身份证最后一位并生成
        String identityNo = CodeUtil.identityNo(prefix);
        return identityNo;
    }

    /**
     * 生成名称
     * @Title: generateNameList
     * @author: dy.yin 2021/8/19 14:31
     */
    @Override
    public String generatePersonName() {
        String name = ChinaUtil.generatePerSonName();
        return name;
    }

    /**
     * 生成公司名称
     * @return
     */
    @Override
    public String generateCompanyName() {
        String name = ChinaUtil.generateCompanyName();
        return name;
    }

    /**
     * 生成手机号
     * @Title: generateMobileList
     * @author: dy.yin 2021/8/19 15:20
     * @param: [num]
     * @return: java.util.List<java.lang.String>
     * @throws
     */
    @Override
    public String generateMobile() {
        String mobileNo = CodeUtil.generateMobileNo();
        return  mobileNo;
    }

    /**
     * 生成地址
     * @Title: generateAddressList
     * @author: dy.yin 2021/8/19 15:20
     * @param: [num]
     * @return: java.util.List<java.lang.String>
     * @throws
     */
    @Override
    public String generateAddress() {
        County county = accountMapper.getRandomCounty();
        return county.getCountyName();
    }

    /**
     * 生成邮政编码
     * @Title: generatePostCodeList
     * @author: dy.yin 2021/8/19 17:35
     */
    @Override
    public String generatePostCode() {
        County county = accountMapper.getRandomCounty();
        return county.getCountyCode();
    }

    /**
     * 组装身份证前17位数字
     * @Title: buildPrefix17
     * @author: dy.yin 2021/8/18 14:49
     * @param: [countyList, birthdayList, locationList, sexList]
     */
    private String buildPrefix17(County county,
                                       String birthday,
                                       String location,
                                       String sex) {

            StringBuilder prefix = new StringBuilder();
            prefix.append(county.getCountyCode())
                    .append(birthday)
                    .append(location)
                    .append(sex);
            return prefix.toString();
    }

    /**
     * 生成transActionAccountId
     * @Title: generateTransActionAccountId
     * @author: dy.yin 2021/8/19 16:21
     */
    @Override
    public String generateTransActionAccountId() {
        String prefix = DateUtil.formatDate(new Date(System.currentTimeMillis()),DateUtil.FORMAT_STR_TIME14);
        String transactionAccountSeq = sequenceUtil.getThreeDigitSequence();
        return prefix + transactionAccountSeq;
    }

    /**
     * 生成账户信息
     * @Title: generateAccountList
     * @author: dy.yin 2021/8/19 17:num
     */
    @Override
    @Async
    public void generateAccountList(int num) {
        LOGGER.info("生成{}个客户开始",num);
        List<Account> accountList = getAccountList(num);
        accountMapper.batchInsertAccount(accountList);
        LOGGER.info("生成{}个客户结束",num);
    }

    @Override
    public List<Account> getAccountList(int num) {
        List<Account> accountList = new ArrayList<>();
        //查询客户类型配置
        List<String> indiOrInst = dictMapper.selectKeysByParentKey("indiOrInst");
        //查询机构证件类型配置
        List<String> instCertificateType = dictMapper.selectKeysByParentKey("instCertificateType");
        //查询个人证件类型配置
        List<String> indiCertificateType = dictMapper.selectKeysByParentKey("indiCertificateType");
        //查询产品证件类型配置
        List<String> fundCertificateType = dictMapper.selectKeysByParentKey("fundCertificateType");

        for (int i = 0; i < num; i++){
            Account account = new Account();
            //投资人交易账号
            String transActionAccountId = generateTransActionAccountId();
            account.setTransactionAccountId(transActionAccountId);
            //客户类型
            Integer indiOrInstIndex = new Random().nextInt(indiOrInst.size());
            String individualOrInstitution = indiOrInst.get(indiOrInstIndex);
            account.setIndividualOrInstitution(individualOrInstitution);
            //证件类型 根据客户类型随机，随机的参数配置查询字典值
            String certificateType = null;
            Integer certificateTypeIndex;
            switch(individualOrInstitution){
                case "0" :
                    certificateTypeIndex = new Random().nextInt(instCertificateType.size());
                    certificateType = instCertificateType.get(certificateTypeIndex);
                    break;
                case "1" :
                    certificateTypeIndex = new Random().nextInt(indiCertificateType.size());
                    certificateType = indiCertificateType.get(certificateTypeIndex);
                    break;
                case "2" :
                    certificateTypeIndex = new Random().nextInt(fundCertificateType.size());
                    certificateType = fundCertificateType.get(certificateTypeIndex);
                    break;
            }

            account.setCertificateType(certificateType);
            //身份证号码
            String identityNo = generateIdentityNo();
            account.setCertificateNo(identityNo);
            //姓名
            String name = generatePersonName();
            if(Objects.equals("0",individualOrInstitution)){//机构
                name = generateCompanyName();
            }
            account.setInvestorName(name);
            //电话
            String mobile = generateMobile();
            account.setMobileNo(mobile);
            //地址
            String address = generateAddress();
            account.setAddress(address);
            //邮编
            String postCode = generatePostCode();
            account.setPostCode(postCode);

            accountList.add(account);
        }
        return accountList;
    }

    /**
     * 渠道开户
     * @param channelCode
     * @param transDate
     * @param transAccounts
     */
    @Override
    public void generateChannelAccount(String channelCode,String transDate,List<Account> transAccounts) {
        LOGGER.info("{}渠道号,基金账号{}",channelCode,transAccounts);
        Channel channel = channelMapper.selectChannelByChannelCode(channelCode);
        List<ChannelAccount> list = new CopyOnWriteArrayList<>();

        transAccounts.forEach(v->{
            ChannelAccount channelAccount = setChannelAccount(v,channel,transDate);
            list.add(channelAccount);
        });
        accountMapper.batchInsertChannelAccount(list);
    }

    /**
     * 组装渠道账户数据
     * @Title: setChannelAccount
     * @author: dy.yin 2021/8/23 15:28
     */
    private ChannelAccount setChannelAccount(Account account,Channel channel,String transActionDate) {

        String appSheetSerialNo = DateUtil.formatDate(new Date(System.currentTimeMillis()),DateUtil.FORMAT_STR_TIME14) + sequenceUtil.getSixDigitSequence();
        String transActionTime = DateUtil.formatDate(new Date(),DateUtil.FORMAT_STR_TIME6);
        String sex = Integer.valueOf(account.getCertificateNo().substring(16,17))%2 == 0 ? "2" : "1";


        String channelCode = channel.getChannelCode();
        String creatorCode = channel.getCreatorCode();

        ChannelAccount channelAccount = new ChannelAccount();
        channelAccount.setChannelCode(channelCode);
        channelAccount.setAppSheetSerialNo(appSheetSerialNo);
        channelAccount.setAddress(account.getAddress());
        channelAccount.setMobileTelNo(account.getMobileNo());
        channelAccount.setIndividualOrInstitution(account.getIndividualOrInstitution());
        channelAccount.setCertificateType(account.getCertificateType());
        channelAccount.setCertificateNo(account.getCertificateNo());
        channelAccount.setInvestorName(account.getInvestorName());
        channelAccount.setTransactionDate(transActionDate);
        channelAccount.setTransactionTime(transActionTime);
        channelAccount.setBusinessCode("001");
        channelAccount.setTransactionAccountId(account.getTransactionAccountId());
        channelAccount.setPostCode(account.getPostCode());
        channelAccount.setDistributorCode(creatorCode);
        channelAccount.setBranchCode(creatorCode);
        channelAccount.setSex(sex);
        return channelAccount;
    }

    @Override
    public List<Account> getAccount(Account account, PageInfo pageInfo) {
        PageUtil.StartPage(pageInfo);
        return accountMapper.getAccount(account,pageInfo);
    }

    @Override
    public void deleteAll() {
        accountMapper.deleteAll();
    }

    @Override
    public void deleteChannelAccountAll() {
        accountMapper.deleteChannelAccountAll();
    }

    @Override
    public List<ChannelAccount> getChannelAccount(ChannelAccount channelAccount, PageInfo pageInfo) {
        PageUtil.StartPage(pageInfo);
        return accountMapper.getChannelAccount(channelAccount,pageInfo);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void generateChannelAccountFile(String channelCode,String transDate, List<String> dateRange) {
        AssembleFileUtil.generateChannelFile(channelCode,transDate,dateRange,ConstUtil.FILE_TYPE_01);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void generateChannelAccountR1File(String channelCode, String transDate, List<String> dateRange) {
        AssembleFileUtil.generateChannelFile(channelCode,transDate,dateRange,ConstUtil.FILE_TYPE_R1);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void generateChannelAccountX1File(String channelCode, String transDate, List<String> dateRange) {
        AssembleFileUtil.generateChannelFile(channelCode,transDate,dateRange,ConstUtil.FILE_TYPE_X1);
    }

    @Override
    public void generateChannelAccountX3File(String channelCode, String transDate, List<String> dateRange) {
        AssembleFileUtil.generateChannelFile(channelCode,transDate,dateRange,ConstUtil.FILE_TYPE_X3);
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    public List<Map<String, Object>> getAccountToMap(String channelCode, List<String> dateRange) {
        return accountMapper.getAccountToMap(channelCode,dateRange);
    }

    @Override
    //TODO
    public List<Map<String, Object>> getAccountR1ToMap(String channelCode, List<String> dateRange) {
        //TODO 暂时没涉及R1的业务，这里返回空
        return new ArrayList<>();//accountMapper.getAccountR1ToMap(channelCode,dateRange);
    }

    @Override
    //TODO
    public List<Map<String, Object>> getAccountX1ToMap(String channelCode, List<String> dateRange) {
        return new ArrayList<>();//accountMapper.getAccountX1ToMap(channelCode,dateRange);
    }

    @Override
    //TODO
    public List<Map<String, Object>> getAccountX3ToMap(String channelCode, List<String> dateRange) {
        return new ArrayList<>();//accountMapper.getAccountX3ToMap(channelCode,dateRange);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void updateChannelAccount(String channelCode, List<Map<String, Object>> dataList) {
        accountMapper.updateChannelAccount(channelCode,dataList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void handleConfirmChannelAccount(String channelCode, List<Map<String, Object>> dataList) {
        //更新账户申请
        updateChannelAccount(channelCode,dataList);
        //开户,插入账户状态表
        List<Map<String, Object>> insertAccountStatus = exchangeChannelAccountList(dataList,ConstUtil.OPEN_ACCOUNT_CONFIRM);
        if(CollectionUtils.isNotEmpty(insertAccountStatus)){
            for (Map<String,Object> map : insertAccountStatus) {
                accountMapper.insertAccountStatus(channelCode,map);
            }
        }
        //修改资料,更新账户状态表
        List<Map<String, Object>> updateAccountStatus = exchangeChannelAccountList(dataList,ConstUtil.UPDATE_ACCOUNT_CONFIRM);
        if(CollectionUtils.isNotEmpty(updateAccountStatus)) {
            accountMapper.updateAccountStatus(channelCode, updateAccountStatus);
        }

    }

    @Transactional(propagation = Propagation.REQUIRED)
    public List<Map<String, Object>> exchangeChannelAccountList(List<Map<String, Object>> dataList, String accountType) {
        List<Map<String, Object>> retList = new ArrayList<>();
        for (Map<String,Object> map : dataList) {
            String businessCode = MapUtils.getString(map,"BUSINESSCODE");
            if(Objects.equals(accountType,businessCode)){
                retList.add(map);
            }
        }
        return retList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void insertChannelAccount(String channelCode, List<Map<String, Object>> dataList) {
        accountMapper.deleteChannelAccount(channelCode,dataList);
        accountMapper.insertChannelAccount(channelCode,dataList);
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    public List<ChannelAccountVo> getChannelAccountAvailable(ChannelAccountVo channelAccount, PageInfo pageInfo) {
        PageUtil.StartPage(pageInfo);
        return accountMapper.getChannelAccountAvailable(channelAccount,pageInfo);
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    public List<AccountStatus> getAccountStatus(AccountStatus accountStatus, PageInfo pageInfo) {
        PageUtil.StartPage(pageInfo);
        return accountMapper.getAccountStatus(accountStatus);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void deleteAllAccountStatus(AccountStatus accountStatus) {
        accountMapper.deleteAllAccountStatus(accountStatus);
    }


    /**
     * 渠道账户信息表插入修改资料记录
     * @param accountStatus 账户状态
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void updateAccountStatus(AccountStatus accountStatus) {
        String channelCode = accountStatus.getChannelCode();
        Channel channel = channelMapper.selectChannelByChannelCode(channelCode);

        String appSheetSerialNo = DateUtil.formatDate(new Date(System.currentTimeMillis()),DateUtil.FORMAT_STR_TIME14) + sequenceUtil.getSixDigitSequence();
        String transActionTime = DateUtil.formatDate(new Date(),DateUtil.FORMAT_STR_TIME6);
        String transActionDate = DateUtil.formatDate(new Date(),DateUtil.FORMAT_STR_TIME8);
        String creatorCode = channel.getCreatorCode();
        String sex = Integer.valueOf(accountStatus.getCertificateNo().substring(16,17))%2 == 0 ? "2" : "1";

        ChannelAccount channelAccount = new ChannelAccount();
        channelAccount.setChannelCode(channelCode);
        channelAccount.setAppSheetSerialNo(appSheetSerialNo);
        channelAccount.setAddress("");
        channelAccount.setMobileTelNo("");
        channelAccount.setPostCode("");
        channelAccount.setIndividualOrInstitution(accountStatus.getIndividualOrInstitution());
        channelAccount.setCertificateType(accountStatus.getCertificateType());
        channelAccount.setCertificateNo(accountStatus.getCertificateNo());
        channelAccount.setInvestorName(accountStatus.getInvestorName());
        channelAccount.setTransactionDate(transActionDate);
        channelAccount.setTransactionTime(transActionTime);
        channelAccount.setBusinessCode("003");
        channelAccount.setTransactionAccountId(accountStatus.getTransactionAccountId());
        channelAccount.setDistributorCode(creatorCode);
        channelAccount.setBranchCode(creatorCode);
        channelAccount.setSex(sex);

        List<ChannelAccount> list = new ArrayList<>();
        list.add(channelAccount);

        accountMapper.batchInsertChannelAccount(list);
    }
}
